﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ActionOperationCut.h"
#include "IUserTransaction.h"
#include "IPickTarget.h"
#include "IPickNodeReferenceAction.h"
#include "IPickFilter.h"
#include "IGraphicsNodeReference.h"
#include "IElementCut.h"
#include "UiDocumentViewUtils.h"
#include "IGenericElement.h"
#include "Wall\Wall.h"
#include "PickNodeReferenceOption.h"
#include "IRegenerator.h"


using namespace Sample;
using namespace gcmp;

namespace
{
    class PickFilter : public gcmp::IPickFilter
    {
    public:
        virtual bool AllowElement(const ElementId& elementId) const override
        {
            if (std::find(m_ids.begin(), m_ids.end(), elementId) != m_ids.end())
            {
                return false;
            }
            IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
            if (pDoc)
            {
                IElement* pElement = pDoc->GetElement(elementId);
                if (const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(pElement))
                {
                    if (const Wall* pWall = quick_cast<const Wall>(pGenericElement->GetExternalObject()))
                        return true;
                }
            }
            return false;
        }

        virtual bool AllowGraphicsNode(const IGraphicsNodeReference& graphicsNodeReference) const override
        {
            return true;
        }

        virtual bool SetPickTargetOption(IPickTarget* pickTarget) override
        {
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pickTarget, L"pickTarget为空", L"GDMP", L"2023-09-30");
            pickTarget->EnableGraphicsElementShape();
            return true;
        }
        void SetUnSelectableElementId(ElementId id)
        {
            m_ids.emplace_back(id);
        }
    private:
        std::vector<ElementId> m_ids;
    };
}

ActionOperationCut::ActionOperationCut()
    :m_selStatus(SelStatus::Not_Sel)
    , m_bIsUserCancelled(false)
{
    SetCursorType(CursorType::ArrowCursor);
}

void ActionOperationCut::InitAction(IUiView* pCurrentView)
{
    SelectCutElement(pCurrentView, GBMP_TR(L"请选择扣减对象"), SelStatus::Getting_StartSel, ElementId::InvalidID);
}

void ActionOperationCut::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    if (m_bIsUserCancelled)
    {
        CleanupTempGraphicsShape();
        UpdateView();
        MarkFinishStatus(ActionFinishStatus::Cancelled);
        return;
    }
    if (m_selStatus == SelStatus::Getting_StartSel && m_graphicsNodeReferences.size() == 1)
    {
        for (auto &nodeReference : m_graphicsNodeReferences)
        {
            m_cutId = nodeReference.get()->GetElementId();
        }
        SelectCutElement(pCurrentView, GBMP_TR(L"请选择被扣减对象"), SelStatus::Getting_EndSel, m_cutId);
        return;
    }
    m_cuteeId = TransferOwnership(m_graphicsNodeReferences.at(0))->GetElementId();

    IDocument *pDocument = UiDocumentViewUtils::GetCurrentDocument();
    OwnerPtr<IUserTransaction> opUserTransaction = IUserTransaction::Create(pDocument, GBMP_TR(L"扣减"));

    IGenericElement* pCutGenericElement = quick_cast<IGenericElement>(pDocument->GetElement(m_cutId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCutGenericElement, L"pCutGenericElement不能为空", L"GDMP", L"2023-09-30");

    Wall* pMyCutterBody = quick_cast<Wall>(pCutGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMyCutterBody, L"pMyCutterBody不能为空", L"GDMP", L"2023-09-30");
    IGenericElement* pCuteeGenericElement = quick_cast<IGenericElement>(pDocument->GetElement(m_cuteeId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCuteeGenericElement, L"pCuteeGenericElement不能为空", L"GDMP", L"2023-09-30");

    Wall* pMyCutteeBody = quick_cast<Wall>(pCuteeGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMyCutteeBody, L"pMyCutteeBody不能为空", L"GDMP", L"2023-09-30");

    //也可以通过CutUtils::BuildElementCutRelationship 建立扣减关系
    IElementCut* elementNewCut = IElementCut::Create(pDocument, pCutGenericElement->GetElementId(), pCuteeGenericElement->GetElementId());

    pMyCutteeBody->MarkDataRdId();
    opUserTransaction->Commit();
    CleanupTempGraphicsShape();
    UpdateView();
    MarkFinishStatus(ActionFinishStatus::Successful);
}

void ActionOperationCut::SelectCutElement(IUiView* pCurrentView, const std::wstring& message, SelStatus selStatus, gcmp::ElementId unSelectableId)
{
    m_selStatus = selStatus;
    SetPromptMessage(message);
    if (m_graphicsNodeReferences.size() > 0)
    {
        m_graphicsNodeReferences.pop_back();
    }

    PickNodeReferenceExchangeData  exchangeData(true, &m_graphicsNodeReferences, &m_bIsUserCancelled);
    OwnerPtr<PickFilter> opPickFilter = NEW_AS_OWNER_PTR(PickFilter);
    if (unSelectableId.IsValid())
    {
        opPickFilter->SetUnSelectableElementId(unSelectableId);
    }
    PickNodeReferenceOption pickOptions;
    pickOptions.SetMultiSelect(false);
    pickOptions.SetCursorType(CursorType::DrawByPick);
    pickOptions.SetMouseTooltipMessage(message);

    OwnerPtr<IAction> opPickNodeReferenceAction = IPickNodeReferenceAction::Create(exchangeData, 
        TransferOwnership(opPickFilter), pickOptions);
    StartChildAction(TransferOwnership(opPickNodeReferenceAction));

}
